1 /*******************************************************************************
2  * Copyright (c) 2000, 2016 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.custom;
15 
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.accessibility.*;
18 import org.eclipse.swt.events.*;
19 import org.eclipse.swt.graphics.*;
20 import org.eclipse.swt.widgets.*;
21 
22 /**
23  * A TableCursor provides a way for the user to navigate around a Table
24  * using the keyboard.  It also provides a mechanism for selecting an
25  * individual cell in a table.
26  * <p>
27  * For a detailed example of using a TableCursor to navigate to a cell and then edit it see
28  * http://git.eclipse.org/c/platform/eclipse.platform.swt.git/tree/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet96.java .
29  *
30  * <dl>
31  * <dt><b>Styles:</b></dt>
32  * <dd>BORDER</dd>
33  * <dt><b>Events:</b></dt>
34  * <dd>Selection, DefaultSelection</dd>
35  * </dl>
36  *
37  * @since 2.0
38  *
39  * @see <a href="http://www.eclipse.org/swt/snippets/#tablecursor">TableCursor snippets</a>
40  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
41  */
42 public class TableCursor extends Canvas {
43 	Table table;
44 	TableItem row = null;
45 	TableColumn column = null;
46 	Listener listener, tableListener, resizeListener, disposeItemListener, disposeColumnListener;
47 
48 	Color background = null;
49 	Color foreground = null;
50 
51 	/* By default, invert the list selection colors */
52 	static final int BACKGROUND = SWT.COLOR_LIST_SELECTION_TEXT;
53 	static final int FOREGROUND = SWT.COLOR_LIST_SELECTION;
54 
55 /**
56  * Constructs a new instance of this class given its parent
57  * table and a style value describing its behavior and appearance.
58  * <p>
59  * The style value is either one of the style constants defined in
60  * class <code>SWT</code> which is applicable to instances of this
61  * class, or must be built by <em>bitwise OR</em>'ing together
62  * (that is, using the <code>int</code> "|" operator) two or more
63  * of those <code>SWT</code> style constants. The class description
64  * lists the style constants that are applicable to the class.
65  * Style bits are also inherited from superclasses.
66  * </p>
67  *
68  * @param parent a Table control which will be the parent of the new instance (cannot be null)
69  * @param style the style of control to construct
70  *
71  * @exception IllegalArgumentException <ul>
72  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
73  * </ul>
74  * @exception SWTException <ul>
75  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
76  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
77  * </ul>
78  *
79  * @see SWT#BORDER
80  * @see Widget#checkSubclass()
81  * @see Widget#getStyle()
82  */
TableCursor(Table parent, int style)83 public TableCursor(Table parent, int style) {
84 	super(parent, style);
85 	table = parent;
86 	setBackground(null);
87 	setForeground(null);
88 
89 	listener = event -> {
90 		switch (event.type) {
91 			case SWT.Dispose :
92 				onDispose(event);
93 				break;
94 			case SWT.FocusIn :
95 			case SWT.FocusOut :
96 				redraw();
97 				break;
98 			case SWT.KeyDown :
99 				keyDown(event);
100 				break;
101 			case SWT.Paint :
102 				paint(event);
103 				break;
104 			case SWT.Traverse : {
105 				event.doit = true;
106 				switch (event.detail) {
107 					case SWT.TRAVERSE_ARROW_NEXT :
108 					case SWT.TRAVERSE_ARROW_PREVIOUS :
109 					case SWT.TRAVERSE_RETURN :
110 						event.doit = false;
111 						break;
112 				}
113 				break;
114 			}
115 		}
116 	};
117 	int[] events = new int[] {SWT.Dispose, SWT.FocusIn, SWT.FocusOut, SWT.KeyDown, SWT.Paint, SWT.Traverse};
118 	for (int event : events) {
119 		addListener(event, listener);
120 	}
121 
122 	tableListener = event -> {
123 		switch (event.type) {
124 			case SWT.MouseDown :
125 				tableMouseDown(event);
126 				break;
127 			case SWT.FocusIn :
128 				tableFocusIn(event);
129 				break;
130 		}
131 	};
132 	table.addListener(SWT.FocusIn, tableListener);
133 	table.addListener(SWT.MouseDown, tableListener);
134 
135 	disposeItemListener = event -> {
136 		unhookRowColumnListeners();
137 		row = null;
138 		column = null;
139 		_resize();
140 	};
141 	disposeColumnListener = event -> {
142 		unhookRowColumnListeners();
143 		row = null;
144 		column = null;
145 		_resize();
146 	};
147 	resizeListener = event -> _resize();
148 	ScrollBar hBar = table.getHorizontalBar();
149 	if (hBar != null) {
150 		hBar.addListener(SWT.Selection, resizeListener);
151 	}
152 	ScrollBar vBar = table.getVerticalBar();
153 	if (vBar != null) {
154 		vBar.addListener(SWT.Selection, resizeListener);
155 	}
156 
157 	getAccessible().addAccessibleControlListener(new AccessibleControlAdapter() {
158 		@Override
159 		public void getRole(AccessibleControlEvent e) {
160 			e.detail = ACC.ROLE_TABLECELL;
161 		}
162 	});
163 	getAccessible().addAccessibleListener(new AccessibleAdapter() {
164 		@Override
165 		public void getName(AccessibleEvent e) {
166 			if (row == null) return;
167 			int columnIndex = column == null ? 0 : table.indexOf(column);
168 			e.result = row.getText(columnIndex);
169 		}
170 	});
171 }
172 
173 /**
174  * Adds the listener to the collection of listeners who will
175  * be notified when the user changes the receiver's selection, by sending
176  * it one of the messages defined in the <code>SelectionListener</code>
177  * interface.
178  * <p>
179  * When <code>widgetSelected</code> is called, the item field of the event object is valid.
180  * If the receiver has <code>SWT.CHECK</code> style set and the check selection changes,
181  * the event object detail field contains the value <code>SWT.CHECK</code>.
182  * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
183  * </p>
184  *
185  * @param listener the listener which should be notified when the user changes the receiver's selection
186  *
187  * @exception IllegalArgumentException <ul>
188  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
189  * </ul>
190  * @exception SWTException <ul>
191  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
192  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
193  * </ul>
194  *
195  * @see SelectionListener
196  * @see SelectionEvent
197  * @see #removeSelectionListener(SelectionListener)
198  *
199  */
addSelectionListener(SelectionListener listener)200 public void addSelectionListener(SelectionListener listener) {
201 	checkWidget();
202 	if (listener == null)
203 		SWT.error(SWT.ERROR_NULL_ARGUMENT);
204 	TypedListener typedListener = new TypedListener(listener);
205 	addListener(SWT.Selection, typedListener);
206 	addListener(SWT.DefaultSelection, typedListener);
207 }
208 
onDispose(Event event)209 void onDispose(Event event) {
210 	removeListener(SWT.Dispose, listener);
211 	notifyListeners(SWT.Dispose, event);
212 	event.type = SWT.None;
213 
214 	table.removeListener(SWT.FocusIn, tableListener);
215 	table.removeListener(SWT.MouseDown, tableListener);
216 	unhookRowColumnListeners();
217 	ScrollBar hBar = table.getHorizontalBar();
218 	if (hBar != null) {
219 		hBar.removeListener(SWT.Selection, resizeListener);
220 	}
221 	ScrollBar vBar = table.getVerticalBar();
222 	if (vBar != null) {
223 		vBar.removeListener(SWT.Selection, resizeListener);
224 	}
225 }
226 
keyDown(Event event)227 void keyDown(Event event) {
228 	if (row == null) return;
229 	switch (event.character) {
230 		case SWT.CR :
231 			notifyListeners(SWT.DefaultSelection, new Event());
232 			return;
233 	}
234 	int rowIndex = table.indexOf(row);
235 	int columnIndex = column == null ? 0 : table.indexOf(column);
236 	switch (event.keyCode) {
237 		case SWT.ARROW_UP :
238 			setRowColumn(Math.max(0, rowIndex - 1), columnIndex, true);
239 			break;
240 		case SWT.ARROW_DOWN :
241 			setRowColumn(Math.min(rowIndex + 1, table.getItemCount() - 1), columnIndex, true);
242 			break;
243 		case SWT.ARROW_LEFT :
244 		case SWT.ARROW_RIGHT :
245 			{
246 				int columnCount = table.getColumnCount();
247 				if (columnCount == 0) break;
248 				int[] order = table.getColumnOrder();
249 				int index = 0;
250 				while (index < order.length) {
251 					if (order[index] == columnIndex) break;
252 					index++;
253 				}
254 				if (index == order.length) index = 0;
255 				int leadKey = (getStyle() & SWT.RIGHT_TO_LEFT) != 0 ? SWT.ARROW_RIGHT : SWT.ARROW_LEFT;
256 				if (event.keyCode == leadKey) {
257 					setRowColumn(rowIndex, order[Math.max(0, index - 1)], true);
258 				} else {
259 					setRowColumn(rowIndex, order[Math.min(columnCount - 1, index + 1)], true);
260 				}
261 				break;
262 			}
263 		case SWT.HOME :
264 			setRowColumn(0, columnIndex, true);
265 			break;
266 		case SWT.END :
267 			{
268 				int i = table.getItemCount() - 1;
269 				setRowColumn(i, columnIndex, true);
270 				break;
271 			}
272 		case SWT.PAGE_UP :
273 			{
274 				int index = table.getTopIndex();
275 				if (index == rowIndex) {
276 					Rectangle rect = table.getClientArea();
277 					TableItem item = table.getItem(index);
278 					Rectangle itemRect = item.getBounds(0);
279 					rect.height -= itemRect.y;
280 					int height = table.getItemHeight();
281 					int page = Math.max(1, rect.height / height);
282 					index = Math.max(0, index - page + 1);
283 				}
284 				setRowColumn(index, columnIndex, true);
285 				break;
286 			}
287 		case SWT.PAGE_DOWN :
288 			{
289 				int index = table.getTopIndex();
290 				Rectangle rect = table.getClientArea();
291 				TableItem item = table.getItem(index);
292 				Rectangle itemRect = item.getBounds(0);
293 				rect.height -= itemRect.y;
294 				int height = table.getItemHeight();
295 				int page = Math.max(1, rect.height / height);
296 				int end = table.getItemCount() - 1;
297 				index = Math.min(end, index + page - 1);
298 				if (index == rowIndex) {
299 					index = Math.min(end, index + page - 1);
300 				}
301 				setRowColumn(index, columnIndex, true);
302 				break;
303 			}
304 	}
305 }
306 
paint(Event event)307 void paint(Event event) {
308 	if (row == null) return;
309 	int columnIndex = column == null ? 0 : table.indexOf(column);
310 	GC gc = event.gc;
311 	gc.setBackground(getBackground());
312 	gc.setForeground(getForeground());
313 	gc.fillRectangle(event.x, event.y, event.width, event.height);
314 	int x = 0;
315 	Point size = getSize();
316 	Image image = row.getImage(columnIndex);
317 	if (image != null) {
318 		Rectangle imageSize = image.getBounds();
319 		int imageY = (size.y - imageSize.height) / 2;
320 		gc.drawImage(image, x, imageY);
321 		x += imageSize.width;
322 	}
323 	String text = row.getText(columnIndex);
324 	if (text.length() > 0) {
325 		Rectangle bounds = row.getBounds(columnIndex);
326 		Point extent = gc.stringExtent(text);
327 		// Temporary code - need a better way to determine table trim
328 		String platform = SWT.getPlatform();
329 		if ("win32".equals(platform)) { //$NON-NLS-1$
330 			if (table.getColumnCount() == 0 || columnIndex == 0) {
331 				x += 2;
332 			} else {
333 				int alignmnent = column.getAlignment();
334 				switch (alignmnent) {
335 					case SWT.LEFT:
336 						x += 6;
337 						break;
338 					case SWT.RIGHT:
339 						x = bounds.width - extent.x - 6;
340 						break;
341 					case SWT.CENTER:
342 						x += (bounds.width - x - extent.x) / 2;
343 						break;
344 				}
345 			}
346 		}  else {
347 			if (table.getColumnCount() == 0) {
348 				x += 5;
349 			} else {
350 				int alignmnent = column.getAlignment();
351 				switch (alignmnent) {
352 					case SWT.LEFT:
353 						x += 5;
354 						break;
355 					case SWT.RIGHT:
356 						x = bounds.width- extent.x - 2;
357 						break;
358 					case SWT.CENTER:
359 						x += (bounds.width - x - extent.x) / 2 + 2;
360 						break;
361 				}
362 			}
363 		}
364 		int textY = (size.y - extent.y) / 2;
365 		gc.drawString(text, x, textY);
366 	}
367 	if (isFocusControl()) {
368 		Display display = getDisplay();
369 		gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
370 		gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
371 		gc.drawFocus(0, 0, size.x, size.y);
372 	}
373 }
374 
tableFocusIn(Event event)375 void tableFocusIn(Event event) {
376 	if (isDisposed()) return;
377 	if (isVisible()) {
378 		if (row == null && column == null) return;
379 		setFocus();
380 	}
381 }
382 
tableMouseDown(Event event)383 void tableMouseDown(Event event) {
384 	if (isDisposed() || !isVisible()) return;
385 	Point pt = new Point(event.x, event.y);
386 	int lineWidth = table.getLinesVisible() ? table.getGridLineWidth() : 0;
387 	TableItem item = table.getItem(pt);
388 	if ((table.getStyle() & SWT.FULL_SELECTION) != 0) {
389 		if (item == null) return;
390 	} else {
391 		int start = item != null ? table.indexOf(item) : table.getTopIndex();
392 		int end = table.getItemCount();
393 		Rectangle clientRect = table.getClientArea();
394 		for (int i = start; i < end; i++) {
395 			TableItem nextItem = table.getItem(i);
396 			Rectangle rect = nextItem.getBounds(0);
397 			if (pt.y >= rect.y && pt.y < rect.y + rect.height + lineWidth) {
398 				item = nextItem;
399 				break;
400 			}
401 			if (rect.y > clientRect.y + clientRect.height) 	return;
402 		}
403 		if (item == null) return;
404 	}
405 	TableColumn newColumn = null;
406 	int columnCount = table.getColumnCount();
407 	if (columnCount == 0) {
408 		if ((table.getStyle() & SWT.FULL_SELECTION) == 0) {
409 			Rectangle rect = item.getBounds(0);
410 			rect.width += lineWidth;
411 			rect.height += lineWidth;
412 			if (!rect.contains(pt)) return;
413 		}
414 	} else {
415 		for (int i = 0; i < columnCount; i++) {
416 			Rectangle rect = item.getBounds(i);
417 			rect.width += lineWidth;
418 			rect.height += lineWidth;
419 			if (rect.contains(pt)) {
420 				newColumn = table.getColumn(i);
421 				break;
422 			}
423 		}
424 		if (newColumn == null) {
425 			if ((table.getStyle() & SWT.FULL_SELECTION) == 0) return;
426 			newColumn = table.getColumn(0);
427 		}
428 	}
429 	setRowColumn(item, newColumn, true);
430 	setFocus();
431 	return;
432 }
setRowColumn(int row, int column, boolean notify)433 void setRowColumn(int row, int column, boolean notify) {
434 	TableItem item = row == -1 ? null : table.getItem(row);
435 	TableColumn col = column == -1 || table.getColumnCount() == 0 ? null : table.getColumn(column);
436 	setRowColumn(item, col, notify);
437 }
setRowColumn(TableItem row, TableColumn column, boolean notify)438 void setRowColumn(TableItem row, TableColumn column, boolean notify) {
439 	if (this.row == row && this.column == column) {
440 		return;
441 	}
442 	if (this.row != null && this.row != row) {
443 		this.row.removeListener(SWT.Dispose, disposeItemListener);
444 		this.row = null;
445 	}
446 	if (this.column != null && this.column != column) {
447 		this.column.removeListener(SWT.Dispose, disposeColumnListener);
448 		this.column.removeListener(SWT.Move, resizeListener);
449 		this.column.removeListener(SWT.Resize, resizeListener);
450 		this.column = null;
451 	}
452 	if (row != null) {
453 		if (this.row != row) {
454 			this.row = row;
455 			row.addListener(SWT.Dispose, disposeItemListener);
456 			table.showItem(row);
457 		}
458 		if (this.column != column && column != null) {
459 			this.column = column;
460 			column.addListener(SWT.Dispose, disposeColumnListener);
461 			column.addListener(SWT.Move, resizeListener);
462 			column.addListener(SWT.Resize, resizeListener);
463 			table.showColumn(column);
464 		}
465 		int columnIndex = column == null ? 0 : table.indexOf(column);
466 		setBounds(row.getBounds(columnIndex));
467 		redraw();
468 		if (notify) {
469 			notifyListeners(SWT.Selection, new Event());
470 		}
471 	}
472 	getAccessible().setFocus(ACC.CHILDID_SELF);
473 }
474 
475 @Override
setVisible(boolean visible)476 public void setVisible(boolean visible) {
477 	checkWidget();
478 	if (visible) _resize();
479 	super.setVisible(visible);
480 }
481 
482 /**
483  * Removes the listener from the collection of listeners who will
484  * be notified when the user changes the receiver's selection.
485  *
486  * @param listener the listener which should no longer be notified
487  *
488  * @exception IllegalArgumentException <ul>
489  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
490  * </ul>
491  * @exception SWTException <ul>
492  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
493  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
494  * </ul>
495  *
496  * @see SelectionListener
497  * @see #addSelectionListener(SelectionListener)
498  *
499  * @since 3.0
500  */
removeSelectionListener(SelectionListener listener)501 public void removeSelectionListener(SelectionListener listener) {
502 	checkWidget();
503 	if (listener == null) {
504 		SWT.error(SWT.ERROR_NULL_ARGUMENT);
505 	}
506 	removeListener(SWT.Selection, listener);
507 	removeListener(SWT.DefaultSelection, listener);
508 }
509 
_resize()510 void _resize() {
511 	if (row == null) {
512 		setBounds(-200, -200, 0, 0);
513 	} else {
514 		int columnIndex = column == null ? 0 : table.indexOf(column);
515 		setBounds(row.getBounds(columnIndex));
516 	}
517 }
518 /**
519  * Returns the index of the column over which the TableCursor is positioned.
520  *
521  * @return the column index for the current position
522  *
523  * @exception SWTException <ul>
524  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
525  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
526  * </ul>
527  */
getColumn()528 public int getColumn() {
529 	checkWidget();
530 	return column == null ? 0 : table.indexOf(column);
531 }
532 /**
533  * Returns the background color that the receiver will use to draw.
534  *
535  * @return the receiver's background color
536  */
537 @Override
getBackground()538 public Color getBackground() {
539 	checkWidget();
540 	if (background == null) {
541 		return getDisplay().getSystemColor(BACKGROUND);
542 	}
543 	return background;
544 }
545 /**
546  * Returns the foreground color that the receiver will use to draw.
547  *
548  * @return the receiver's foreground color
549  */
550 @Override
getForeground()551 public Color getForeground() {
552 	checkWidget();
553 	if (foreground == null) {
554 		return getDisplay().getSystemColor(FOREGROUND);
555 	}
556 	return foreground;
557 }
558 /**
559  * Returns the row over which the TableCursor is positioned.
560  *
561  * @return the item for the current position, or <code>null</code> if none
562  *
563  * @exception SWTException <ul>
564  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
565  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
566  * </ul>
567  */
getRow()568 public TableItem getRow() {
569 	checkWidget();
570 	return row;
571 }
572 /**
573  * Sets the receiver's background color to the color specified
574  * by the argument, or to the default system color for the control
575  * if the argument is null.
576  * <p>
577  * Note: This operation is a hint and may be overridden by the platform.
578  * For example, on Windows the background of a Button cannot be changed.
579  * </p>
580  * @param color the new color (or null)
581  *
582  * @exception IllegalArgumentException <ul>
583  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
584  * </ul>
585  * @exception SWTException <ul>
586  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
587  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
588  * </ul>
589  */
590 @Override
setBackground(Color color)591 public void setBackground (Color color) {
592 	background = color;
593 	super.setBackground(getBackground());
594 	redraw();
595 }
596 /**
597  * Sets the receiver's foreground color to the color specified
598  * by the argument, or to the default system color for the control
599  * if the argument is null.
600  * <p>
601  * Note: This operation is a hint and may be overridden by the platform.
602  * </p>
603  * @param color the new color (or null)
604  *
605  * @exception IllegalArgumentException <ul>
606  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
607  * </ul>
608  * @exception SWTException <ul>
609  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
610  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
611  * </ul>
612  */
613 @Override
setForeground(Color color)614 public void setForeground (Color color) {
615 	foreground = color;
616 	super.setForeground(getForeground());
617 	redraw();
618 }
619 /**
620  * Positions the TableCursor over the cell at the given row and column in the parent table.
621  *
622  * @param row the index of the row for the cell to select
623  * @param column the index of column for the cell to select
624  *
625  * @exception SWTException <ul>
626  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
627  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
628  * </ul>
629  *
630  */
setSelection(int row, int column)631 public void setSelection(int row, int column) {
632 	checkWidget();
633 	int columnCount = table.getColumnCount();
634 	int maxColumnIndex =  columnCount == 0 ? 0 : columnCount - 1;
635 	if (row < 0
636 		|| row >= table.getItemCount()
637 		|| column < 0
638 		|| column > maxColumnIndex)
639 		SWT.error(SWT.ERROR_INVALID_ARGUMENT);
640 	setRowColumn(row, column, false);
641 }
642 /**
643  * Positions the TableCursor over the cell at the given row and column in the parent table.
644  *
645  * @param row the TableItem of the row for the cell to select
646  * @param column the index of column for the cell to select
647  *
648  * @exception SWTException <ul>
649  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
650  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
651  * </ul>
652  *
653  */
setSelection(TableItem row, int column)654 public void setSelection(TableItem row, int column) {
655 	checkWidget();
656 	int columnCount = table.getColumnCount();
657 	int maxColumnIndex =  columnCount == 0 ? 0 : columnCount - 1;
658 	if (row == null
659 		|| row.isDisposed()
660 		|| column < 0
661 		|| column > maxColumnIndex)
662 		SWT.error(SWT.ERROR_INVALID_ARGUMENT);
663 	setRowColumn(table.indexOf(row), column, false);
664 }
unhookRowColumnListeners()665 void unhookRowColumnListeners() {
666 	if (column != null) {
667 		column.removeListener(SWT.Dispose, disposeColumnListener);
668 		column.removeListener(SWT.Move, resizeListener);
669 		column.removeListener(SWT.Resize, resizeListener);
670 		column = null;
671 	}
672 	if (row != null) {
673 		row.removeListener(SWT.Dispose, disposeItemListener);
674 		row = null;
675 	}
676 }
677 }
678